package entity

import (
	lock "YingShop/Lock"
	dbconnector "YingShop/dbConnector"
	"YingShop/enum"
	"YingShop/log"
	"YingShop/model"
	querystruct "YingShop/queryStruct"
	responsestruct "YingShop/responseStruct"
	"YingShop/utils"
	"errors"
	"fmt"
	"sort"
	"time"

	"gorm.io/gorm"
)

type ShopOrder struct {
	OrderId         int
	OrderPrice      float64
	OrderCreator    string
	OrderCreateTime string
	OrderUpdateTime string
	OrderStatus     int
	OrderCreatorId  int
}

func (order *ShopOrder) Load() error {
	conn := dbconnector.GetDb()
	orderModel := model.ShopOrder{}
	result := conn.First(&orderModel, order.OrderId)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			return fmt.Errorf("找不到id为%d的订单", orderModel.OrderId)
		} else {
			log.Error(result.Error.Error())
			return errors.New("未知错误")
		}
	}
	order.OrderPrice = orderModel.OrderPrice
	order.OrderCreator = orderModel.OrderCreator
	order.OrderCreateTime = utils.TimeFormatToNormal(orderModel.OrderCreateTime)
	order.OrderUpdateTime = utils.TimeFormatToNormal(orderModel.OrderUpdateTime)
	order.OrderStatus = orderModel.OrderStatus
	return nil
}

func (order *ShopOrder) Create(orderReq querystruct.OrderCreateParam) error {
	conn := dbconnector.GetDb()
	conn = conn.Begin()
	productModelList := make([]model.ShopProduct, 0)
	productIdList := make([]int, 0)
	productIdAndNumMap := make(map[int]int, 0)
	// 订单数据处理，获取商品id列表和各商品个数
	for _, value := range orderReq.ProductList {
		productIdList = append(productIdList, value.ProdutId)
		productIdAndNumMap[value.ProdutId] = value.ProductNum
	}
	// 对商品id进行排序，用于接下来的按序获取锁
	sort.Ints(productIdList)
	result := conn.Where(productIdList).Find(&productModelList)
	if result.Error != nil {
		log.Error(fmt.Sprintf("创建订单时查询商品详情出错:%s, productIdList:%v", result.Error, productIdList))
		conn.Rollback()
		return fmt.Errorf("创建订单时发生未知错误")
	}
	if len(productModelList) != len(productIdList) {
		conn.Rollback()
		return fmt.Errorf("部分商品找不到，请重新确认")
	}
	orderPrice := 0.0
	for _, value := range productModelList {
		productNum := productIdAndNumMap[value.ProductId]
		orderPrice += value.ProductPrice * float64(productNum)
	}
	// 创建订单
	orderModel := model.ShopOrder{}
	orderModel.OrderCreator = order.OrderCreator
	orderModel.OrderPrice = orderPrice
	orderModel.OrderCreatorId = order.OrderCreatorId
	orderModel.OrderStatus = enum.WaitingForPayment
	result = conn.Create(&orderModel)
	if result.Error != nil {
		log.Error(fmt.Sprintf("创建订单时出错:%s, productIdList:%v", result.Error, productIdList))
		conn.Rollback()
		return fmt.Errorf("创建订单时发生未知错误")
	}
	order.OrderId = orderModel.OrderId
	// 创建商品和订单映射
	orderProductRelationList := make([]model.ProductOrderRelation, 0)
	for _, productId := range productIdList {
		orderProduct := model.ProductOrderRelation{}
		orderProduct.OrderId = orderModel.OrderId
		orderProduct.ProductId = productId
		orderProduct.ProductNum = productIdAndNumMap[productId]
		orderProductRelationList = append(orderProductRelationList, orderProduct)
	}
	result = conn.Create(&orderProductRelationList)
	if result.Error != nil {
		log.Error(fmt.Sprintf("创建订单商品映射关系时出错:%s, orderProductRelationList:%v", result.Error, orderProductRelationList))
		conn.Rollback()
		return fmt.Errorf("创建订单时发生未知错误")
	}
	// 锁库存
	productLockList := make([]lock.ShopProductLock, 0)
	// 先把所有商品的锁获取到
	for _, productId := range productIdList {
		productLock := lock.GetShopProductLock(productId)
		begin := time.Now().Unix()
		acquireStatus := 0
		for {
			lockErr := productLock.Lock()
			if lockErr != nil {
				// 100毫秒后重试
				time.Sleep(100 * time.Millisecond)
			} else {
				acquireStatus = 1
				productLockList = append(productLockList, productLock)
				break
			}
			// 3秒钟没有获取到锁，返回失败
			if time.Now().Unix()-begin > 3 {
				break
			}
		}
		// 有锁获取失败，返回下订失败
		if acquireStatus != 1 {
			for _, readyLock := range productLockList {
				readyLock.UnLock()
			}
			log.Error(fmt.Sprintf("id为%d的商品获取锁失败", productId))
			conn.Rollback()
			return fmt.Errorf("系统繁忙，请稍后再试")
		}
	}
	// 修改库存
	for _, productId := range productIdList {
		retryTimes := 3
		for {
			productModel := model.ShopProduct{}
			conn.First(&productModel, productId)
			curVersion := productModel.ProductVersion
			curProductNum := productModel.ProductNum
			if curProductNum < productIdAndNumMap[productId] {
				for _, readyLock := range productLockList {
					readyLock.UnLock()
				}
				errInfo := fmt.Sprintf("id为%d的商品库存为%d,小于%d", productId, curProductNum, productIdAndNumMap[productId])
				log.Error(errInfo)
				conn.Rollback()
				return fmt.Errorf("%s", errInfo)
			}
			productModel.ProductNum -= productIdAndNumMap[productId]
			productModel.ProductVersion += 1
			result := conn.Model(&productModel).Where("product_version = ?", curVersion).Select("product_version", "product_num").Updates(productModel)
			if result.Error != nil {
				for _, readyLock := range productLockList {
					readyLock.UnLock()
				}
				errInfo := fmt.Sprintf("锁定id为%d的商品库存时出错:%s", productId, result.Error)
				log.Error(errInfo)
				conn.Rollback()
				return fmt.Errorf("系统出现未知错误，请稍后再试")
			}
			if result.RowsAffected == 1 {
				break
			} else if result.RowsAffected > 1 {
				for _, readyLock := range productLockList {
					readyLock.UnLock()
				}
				errInfo := fmt.Sprintf("锁定id为%d的商品库存时出错:%s", productId, "影响行数大于1")
				log.Error(errInfo)
				conn.Rollback()
				return fmt.Errorf("系统出现未知错误，请稍后再试")
			}
			retryTimes -= 1
		}

	}
	for _, readyLock := range productLockList {
		readyLock.UnLock()
	}
	conn.Commit()

	return nil

}

func (order *ShopOrder) GetOrderProductList() (orderProductList []responsestruct.OrderProductInfo, err error) {
	conn := dbconnector.GetDb()
	orderProductModelList := make([]model.ProductOrderRelation, 0)
	// 获取订单下的所有商品映射关系
	result := conn.Where(&model.ShopOrder{OrderId: order.OrderId}).Find(&orderProductModelList)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			err = fmt.Errorf("找不到id为%d的订单商品", order.OrderId)
			return
		} else {
			log.Error(result.Error.Error())
			err = errors.New("未知错误")
			return
		}
	}
	productIdList := make([]int, 0)
	for _, relation := range orderProductModelList {
		productIdList = append(productIdList, relation.ProductId)
	}
	productModelList := make([]model.ShopProduct, 0)
	// 获取订单下的所有商品详情
	result = conn.Find(&productModelList, productIdList)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			err = fmt.Errorf("找不到id为%d的订单商品详情", order.OrderId)
			return
		} else {
			log.Error(result.Error.Error())
			err = errors.New("未知错误")
			return
		}
	}
	productModelMap := make(map[int]model.ShopProduct, 0)
	for _, value := range productModelList {
		productModelMap[value.ProductId] = value
	}
	// 组装查询结果
	for _, relation := range orderProductModelList {
		orderProduct := responsestruct.OrderProductInfo{}
		orderProduct.ProductName = productModelMap[relation.ProductId].ProductName
		orderProduct.ProductNum = relation.ProductNum
		orderProduct.ProductPrice = productModelMap[relation.ProductId].ProductPrice
		orderProduct.ProductName = productModelMap[relation.ProductId].ProductName
		orderProduct.ProductId = relation.ProductId
		orderProductList = append(orderProductList, orderProduct)
	}

	return
}

func (order *ShopOrder) Pay() error {
	// 模拟支付订单
	conn := dbconnector.GetDb()
	orderLock := lock.GetOrderProductLock(order.OrderId)
	// 获取锁
	acquireStatus := 0
	begin := time.Now().Unix()
	for {
		lockErr := orderLock.Lock()
		if lockErr != nil {
			// 100毫秒后重试
			time.Sleep(100 * time.Millisecond)
		} else {
			acquireStatus = 1
			break
		}
		// 3秒钟没有获取到锁，返回失败
		if time.Now().Unix()-begin > 3 {
			break
		}
	}
	if acquireStatus != 1 {
		return fmt.Errorf("系统繁忙，请稍后再试")
	}
	orderModel := model.ShopOrder{OrderId: order.OrderId}
	result := conn.First(&orderModel, order.OrderId)
	if result.Error != nil {
		orderLock.UnLock()
		return fmt.Errorf("订单不存在")
	}
	orderVersion := orderModel.OrderVersion
	orderModel.OrderVersion = orderVersion + 1
	orderModel.OrderStatus = enum.Paied
	for {
		result = conn.Model(orderModel).Where(&model.ShopOrder{
			OrderId:      order.OrderId,
			OrderVersion: orderVersion,
		}).Select("order_version", "order_status").Updates(orderModel)
		if result.Error != nil {
			log.Error(result.Error.Error())
			orderLock.UnLock()
			return fmt.Errorf("出现未知错误")
		}
		if result.RowsAffected != 0 {
			break
		}
	}
	return nil
}

func (order *ShopOrder) Accept() error {
	// 模拟支付订单
	conn := dbconnector.GetDb()
	orderLock := lock.GetOrderProductLock(order.OrderId)
	// 获取锁
	acquireStatus := 0
	begin := time.Now().Unix()
	for {
		lockErr := orderLock.Lock()
		if lockErr != nil {
			// 100毫秒后重试
			time.Sleep(100 * time.Millisecond)
		} else {
			acquireStatus = 1
			break
		}
		// 3秒钟没有获取到锁，返回失败
		if time.Now().Unix()-begin > 3 {
			break
		}
	}
	if acquireStatus != 1 {
		return fmt.Errorf("系统繁忙，请稍后再试")
	}
	orderModel := model.ShopOrder{OrderId: order.OrderId}
	result := conn.First(&orderModel, order.OrderId)
	if result.Error != nil {
		orderLock.UnLock()
		return fmt.Errorf("订单不存在")
	}
	orderVersion := orderModel.OrderVersion
	orderModel.OrderVersion = orderVersion + 1
	orderModel.OrderStatus = enum.Accepted
	for {

		result = conn.Model(orderModel).Where(&model.ShopOrder{
			OrderId:      order.OrderId,
			OrderVersion: orderVersion,
		}).Select("order_version", "order_status").Updates(orderModel)
		if result.Error != nil {
			log.Error(result.Error.Error())
			orderLock.UnLock()
			return fmt.Errorf("出现未知错误")
		}
		if result.RowsAffected != 0 {
			break
		}
	}
	return nil
}

func (order *ShopOrder) Making() error {
	// 模拟支付订单
	conn := dbconnector.GetDb()
	orderLock := lock.GetOrderProductLock(order.OrderId)
	// 获取锁
	acquireStatus := 0
	begin := time.Now().Unix()
	for {
		lockErr := orderLock.Lock()
		if lockErr != nil {
			// 100毫秒后重试
			time.Sleep(100 * time.Millisecond)
		} else {
			acquireStatus = 1
			break
		}
		// 3秒钟没有获取到锁，返回失败
		if time.Now().Unix()-begin > 3 {
			break
		}
	}
	if acquireStatus != 1 {
		return fmt.Errorf("系统繁忙，请稍后再试")
	}
	orderModel := model.ShopOrder{OrderId: order.OrderId}
	result := conn.First(&orderModel, order.OrderId)
	if result.Error != nil {
		orderLock.UnLock()
		return fmt.Errorf("订单不存在")
	}
	orderVersion := orderModel.OrderVersion
	orderModel.OrderVersion = orderVersion + 1
	orderModel.OrderStatus = enum.Making
	for {

		result = conn.Model(orderModel).Where(&model.ShopOrder{
			OrderId:      order.OrderId,
			OrderVersion: orderVersion,
		}).Select("order_version", "order_status").Updates(orderModel)
		if result.Error != nil {
			log.Error(result.Error.Error())
			orderLock.UnLock()
			return fmt.Errorf("出现未知错误")
		}
		if result.RowsAffected != 0 {
			break
		}
	}
	return nil
}

func (order *ShopOrder) Ready() error {
	// 模拟支付订单
	conn := dbconnector.GetDb()
	orderLock := lock.GetOrderProductLock(order.OrderId)
	// 获取锁
	acquireStatus := 0
	begin := time.Now().Unix()
	for {
		lockErr := orderLock.Lock()
		if lockErr != nil {
			// 100毫秒后重试
			time.Sleep(100 * time.Millisecond)
		} else {
			acquireStatus = 1
			break
		}
		// 3秒钟没有获取到锁，返回失败
		if time.Now().Unix()-begin > 3 {
			break
		}
	}
	if acquireStatus != 1 {
		return fmt.Errorf("系统繁忙，请稍后再试")
	}
	orderModel := model.ShopOrder{OrderId: order.OrderId}
	result := conn.First(&orderModel, order.OrderId)
	if result.Error != nil {
		orderLock.UnLock()
		return fmt.Errorf("订单不存在")
	}
	orderVersion := orderModel.OrderVersion
	orderModel.OrderVersion = orderVersion + 1
	orderModel.OrderStatus = enum.Ready
	for {

		result = conn.Model(orderModel).Where(&model.ShopOrder{
			OrderId:      order.OrderId,
			OrderVersion: orderVersion,
		}).Select("order_version", "order_status").Updates(orderModel)
		if result.Error != nil {
			log.Error(result.Error.Error())
			orderLock.UnLock()
			return fmt.Errorf("出现未知错误")
		}
		if result.RowsAffected != 0 {
			break
		}
	}
	return nil
}

func (order *ShopOrder) Finish() error {
	// 模拟支付订单
	conn := dbconnector.GetDb()
	orderLock := lock.GetOrderProductLock(order.OrderId)
	// 获取锁
	acquireStatus := 0
	begin := time.Now().Unix()
	for {
		lockErr := orderLock.Lock()
		if lockErr != nil {
			// 100毫秒后重试
			time.Sleep(100 * time.Millisecond)
		} else {
			acquireStatus = 1
			break
		}
		// 3秒钟没有获取到锁，返回失败
		if time.Now().Unix()-begin > 3 {
			break
		}
	}
	if acquireStatus != 1 {
		return fmt.Errorf("系统繁忙，请稍后再试")
	}
	orderModel := model.ShopOrder{OrderId: order.OrderId}
	result := conn.First(&orderModel, order.OrderId)
	if result.Error != nil {
		orderLock.UnLock()
		return fmt.Errorf("订单不存在")
	}
	orderVersion := orderModel.OrderVersion
	orderModel.OrderVersion = orderVersion + 1
	orderModel.OrderStatus = enum.Finished
	for {

		result = conn.Model(orderModel).Where(&model.ShopOrder{
			OrderId:      order.OrderId,
			OrderVersion: orderVersion,
		}).Select("order_version", "order_status").Updates(orderModel)
		if result.Error != nil {
			log.Error(result.Error.Error())
			orderLock.UnLock()
			return fmt.Errorf("出现未知错误")
		}
		if result.RowsAffected != 0 {
			break
		}
	}
	return nil
}
